# -*- coding: utf-8 -*-
#模板匹配

from enum import Enum

import cv2
import numpy as np
from PIL import Image
from numba import jit
import sys
sys.setrecursionlimit(2000)
def hexstr_16_to_hexstr_2(hex_str):
    x = bin(int('1'+hex_str, 16))[3:]#含有前导0的转换
    return x

ascii_char = list("0@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'.1")

def get_char(r,g,b,alpha=256):#alpha透明度
    if alpha==0:
        return ' '
    length=len(ascii_char)
    gray=int(0.2126*r+0.7152*g+0.0722*b)#计算灰度
    unit=(256.0+1)/length
    return ascii_char[int(gray/unit)]#不同的灰度对应着不同的字符

# 16进制颜色格式颜色转换为RGB格式
def Hex_to_RGB(hex):
    r = int(hex[2:4], 16)
    g = int(hex[4:6], 16)
    b = int(hex[6:8], 16)
    # rgb = str(r)+','+str(g)+','+str(b)
    # print(rgb)
    return r, g, b


class State(Enum):
    OK = 1
    ERROR = 2
    ROLLBACK = 3
    NOTMATCH = 4


def binstr_to_nparray(hex_2_str,abs_x,abs_y):
    binary = np.zeros((abs_y,abs_x), dtype=np.uint8)
    #print("hex_2_str:{0} len:{1}".format(hex_2_str,len(hex_2_str)))
    #display(hex_2_str,abs_x,abs_y,"")
    i = 0
    for j in range(abs_x):
        for k in range(abs_y):
            if hex_2_str[i] == "0":
                binary[k][j]=0
            else:
                binary[k][j]=255
            i+=1
    return binary


# rgb误差函数，反正是从pyscreeze这上面抄的魔改的
def pixelMatchesColor(pix, expectedRGBColor, tolerance=0):
    """
    TODO
    """
    if len(pix) == 3 and len(expectedRGBColor) == 3:  # RGB mode
        r, g, b = pix[:3]
        exR, exG, exB = expectedRGBColor[:3]
        return (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance)
    else:
        assert False, 'Color mode was expected to be length 3 (RGB) or 4 (RGBA), but pixel is length %s and expectedRGBColor is length %s' % (
        len(pix), len(expectedRGBColor))






class Robot:
    def __init__(self):
        pass

    @staticmethod
    @jit
    def __findMultiColor(s_c, expectedRGBColor, tolerance, x1=None, y1=None, x2=None, y2=None):
        pos_x_y = []
        for y in range(y1, y2):
            for x in range(x1, x2):
                b, g, r = s_c[y, x]
                exR, exG, exB = expectedRGBColor[:3]
                if (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance):
                    pos_x_y.append((x, y))
        return pos_x_y

        # 像素转换成二值化点阵，返回二进制字符串

    @staticmethod
    @jit
    def rgb_to_hexstr_2(image_arrays, binary, MeanRgb, x1, y1, x2, y2):
        for idx, x in enumerate(range(x1, x2)):
            for idy, y in enumerate(range(y1, y2)):
                b, g, r = image_arrays[y, x]
                for m in MeanRgb:
                    __mean_s_r = m[0]
                    __mean_s_g = m[1]
                    __mean_s_b = m[2]
                    __mean_m_r = m[3]
                    __mean_m_g = m[4]
                    __mean_m_b = m[5]
                    if r <= (__mean_s_r + __mean_m_r) and r >= (__mean_s_r - __mean_m_r) and g <= (
                            __mean_s_g + __mean_m_g) and g >= (__mean_s_g - __mean_m_g) and b <= (
                            __mean_s_b + __mean_m_b) and b >= (__mean_s_b - __mean_m_b):
                        binary[idy, idx] = 255
                        break
                    else:
                        binary[idy, idx] = 0

        return binary

    """
      x,y = findMultiColorInRegionFuzzy( "0xed1d60", "14|-7|0xb1cdf0,21|4|0xe2df73", 90, 0, 0, 1279, 719)
    """

    def findMultiColorInRegionFuzzy(self, tpl,color, posandcolor, degree, x1=None, y1=None, x2=None, y2=None, tab=None,
                                    islist=False):
        x = None
        y = None
        tolerance = 100 - degree
        r, g, b = Hex_to_RGB(color)
        posandcolor_list = list()
        posandcolors_param = posandcolor.split(",")
        for p in posandcolors_param:
            __c = p.split("|")
            px = __c[0]
            py = __c[1]
            rgb_hex = __c[2]
            _tmp = {"px": int(px), "py": int(py), "rgb_hex": rgb_hex}
            posandcolor_list.append(_tmp)
        state = State.OK
        pos_x_y_list = self.__findMultiColor(tpl, (r, g, b), tolerance, x1, y1, x2, y2)
        if pos_x_y_list:
            for x, y in pos_x_y_list:
                for p in posandcolor_list:
                    newY = int(p["py"]) + y
                    newX = int(p["px"]) + x

                    __rgb_hex = p["rgb_hex"]
                    if newY < y1 or newY > y2:
                        state = State.NOTMATCH
                        break
                    if newX < x1 or newX > x2:
                        state = State.NOTMATCH
                        break
                    b, g, r = tpl[newY, newX]
                    exR = int(__rgb_hex[2:4], 16)
                    exG = int(__rgb_hex[4:6], 16)
                    exB = int(__rgb_hex[6:8], 16)

                    if (pixelMatchesColor((r, g, b), (exR, exG, exB), tolerance)):
                        state = State.OK

                    else:
                        state = State.NOTMATCH
                        break
                if state == State.OK:
                    return x , y
        return -1, -1

    def x_Ocrtext(self, tpl,tabs, scx_rgb, x1, y1, x2, y2, similarity=0.6):
        # ret = re.findall(r"@(.*?)\$",tab,re.I|re.M)
        image_array1 = self.__Ocr(tpl,scx_rgb, x1, y1, x2, y2)
        for tab in tabs:
            if "@" in tab:
                data_tuple = tab.split("@")[1]
                hex_str_16 = tab.split("@")[0]
            else:
                data_tuple = tab
                hex_str_16 = tab.split("$")[0]
            data_tuple = data_tuple.split("$")
            if len(data_tuple):
                p_hexstr_2 = data_tuple[0]
                hexstr_2 = hexstr_16_to_hexstr_2(hex_str_16)
                hexstr_2 += p_hexstr_2
                word = data_tuple[1]
                x = int(data_tuple[4])
                y = int(data_tuple[3])
                image_array = binstr_to_nparray(hexstr_2, x, y)
                new_X_t = self.matchTemplate(image_array1, image_array, similarity)
                print(new_X_t)
                if new_X_t != (-1, -1):
                    print("当前识字为:{0}".format(word))
                    return word
        print('字库识别为空')
        return ""

    def Ocrtext(self,tpl, tabs, scx_rgb, x1, y1, x2, y2, jiange=1, M=0.1):
        # ret = re.findall(r"@(.*?)\$",tab,re.I|re.M)
        textline = list()
        m_textline = list()
        z_textline = list()
        strs = ""
        image_array1 = self.__Ocr(tpl,scx_rgb, x1, y1, x2, y2)
        # 4、分割字符
        white = []  # 记录每一列的白色像素总和
        black = []  # ..........黑色.......
        height = image_array1.shape[0]
        width = image_array1.shape[1]
        white_max = 0
        black_max = 0
        # 计算每一列的黑白色像素总和
        for i in range(width):
            s = 0  # 这一列白色总数
            t = 0  # 这一列黑色总数
            for j in range(height):
                if image_array1[j][i] == 255:
                    s += 1
                if image_array1[j][i] == 0:
                    t += 1
            white_max = max(white_max, s)
            black_max = max(black_max, t)
            white.append(s)
            black.append(t)
            # print(s)
            # print(t)
        arg = False  # False表示白底黑字；True表示黑底白字
        if black_max > white_max:
            arg = True

        # 分割图像
        def find_end(start_):
            end_ = start_ + 1
            for m in range(start_ + 1, width - 1):
                if (black[m] if arg else white[m]) > (
                0.95 * black_max if arg else 0.95 * white_max):  # 0.95这个参数请多调整，对应下面的0.05
                    end_ = m
                    break
            return end_

        n = 1
        start = 1
        end = 2
        ___i = 0
        while n < width - 2:
            n += 1
            if (white[n] if arg else black[n]) > (0.05 * white_max if arg else 0.05 * black_max):
                # 上面这些判断用来辨别是白底黑字还是黑底白字
                # 0.05这个参数请多调整，对应上面的0.95
                start = n
                end = find_end(start)
                n = end
                if end - start > 1:
                    cj = image_array1[1:height + 2, start:end + 1]
                    ok = False
                    if ___i == 6:
                        ok = True
                        # self.show(cj)
                    ___i += 1
                    bno_found = True
                    for tab in tabs:
                        if "@" in tab:
                            data_tuple = tab.split("@")[1]
                            hex_str_16 = tab.split("@")[0]
                        else:
                            data_tuple = tab
                            hex_str_16 = tab.split("$")[0]
                        data_tuple = data_tuple.split("$")
                        if len(data_tuple):
                            bk = False
                            p_hexstr_2 = data_tuple[0]
                            hexstr_2 = hexstr_16_to_hexstr_2(hex_str_16)
                            if hex_str_16 == "c00000c00000c1ff00c78000ec0000f80000f0000040000":
                                # print("find it")
                                if ok:
                                    bk = True
                                # print(len(hexstr_2))
                            if "@" in tab:
                                c = p_hexstr_2
                                c += hexstr_2
                                hexstr_2 = c
                            word = data_tuple[1]
                            x = int(data_tuple[4])
                            y = int(data_tuple[3])
                            image_array = binstr_to_nparray(hexstr_2, x, y)
                            if bk:
                                pass
                                # self.show(image_array)
                            new_X_t = self.matchTemplate(cj, image_array, M, getone=True)
                            if new_X_t != (-1, -1):
                                strs += word
                                bno_found = False
                                break
                    if bno_found:
                        strs += "?"
        print("当前字符串:", strs)
        return strs

    def Ocrtext_featrue(self,tpl, tabs, scx_rgb, x1, y1, x2, y2, jiange=1, M=0.1):
        # ret = re.findall(r"@(.*?)\$",tab,re.I|re.M)
        textline = list()
        m_textline = list()
        z_textline = list()
        strs = ""
        image_array1 = self.__Ocr(tpl,scx_rgb, x1, y1, x2, y2)
        # 4、分割字符
        white = []  # 记录每一列的白色像素总和
        black = []  # ..........黑色.......
        height = image_array1.shape[0]
        width = image_array1.shape[1]
        white_max = 0
        black_max = 0
        # 计算每一列的黑白色像素总和
        for i in range(width):
            s = 0  # 这一列白色总数
            t = 0  # 这一列黑色总数
            for j in range(height):
                if image_array1[j][i] == 255:
                    s += 1
                if image_array1[j][i] == 0:
                    t += 1
            white_max = max(white_max, s)
            black_max = max(black_max, t)
            white.append(s)
            black.append(t)
            # print(s)
            # print(t)
        arg = False  # False表示白底黑字；True表示黑底白字
        if black_max > white_max:
            arg = True

        # 分割图像
        def find_end(start_):
            end_ = start_ + 1
            for m in range(start_ + 1, width - 1):
                if (black[m] if arg else white[m]) > (
                0.95 * black_max if arg else 0.95 * white_max):  # 0.95这个参数请多调整，对应下面的0.05
                    end_ = m
                    break
            return end_

        n = 1
        start = 1
        end = 2
        ___i = 0
        with open('featrue.txt', "w+") as f:
            while n < width - 2:
                n += 1
                if (white[n] if arg else black[n]) > (0.05 * white_max if arg else 0.05 * black_max):
                    # 上面这些判断用来辨别是白底黑字还是黑底白字
                    # 0.05这个参数请多调整，对应上面的0.95
                    start = n
                    end = find_end(start)
                    n = end
                    if end - start > 1:
                        cj = image_array1[1:height + 2, start:end + 1]
                        ok = False
                        if ___i == 6:
                            ok = True
                            # self.show(cj)
                        ___i += 1
                        im = Image.fromarray(np.uint8(cj)).convert('RGB')
                        txt = ""
                        mdsad = ""
                        for i in range(im.size[0]):
                            for j in range(im.size[1]):
                                cxzc = get_char(*im.getpixel((i, j)))
                                txt += cxzc
                                mdsad += cxzc
                            txt += '\n'
                        # onecomp = im.size[0]*im.size[1] - len(hexstr_16_to_hexstr_2(ont)) #补码
                        mdsad += '$' + str(im.size[1]) + '$' + str(im.size[0]) + '\n'
                        items = mdsad.split("$")
                        featrue = items[0]
                        height = int(items[1])
                        wight = int(items[2])
                        ont = hex(int(featrue, 2))[2:]
                        onecomp = height * wight - len(hexstr_16_to_hexstr_2(ont))  # 补码
                        print("补码：{0} 个 0".format(onecomp))
                        z = "@"
                        for i in range(0, onecomp):
                            z += "0"
                        # zz = featrue[:] + z
                        featrue = featrue[:]
                        print(str(hex(int(featrue, 2)) + z + "$?$?$" + items[1] + "$" + items[2]))
                        f.write(str(hex(int(featrue, 2)) + z + "$?$?$" + items[1] + "$" + items[2]))
                        print(txt)
                        bno_found = True
                        for tab in tabs:
                            if "@" in tab:
                                data_tuple = tab.split("@")[1]
                                hex_str_16 = tab.split("@")[0]
                            else:
                                data_tuple = tab
                                hex_str_16 = tab.split("$")[0]
                            data_tuple = data_tuple.split("$")
                            if len(data_tuple):
                                bk = False
                                p_hexstr_2 = data_tuple[0]
                                hexstr_2 = hexstr_16_to_hexstr_2(hex_str_16)
                                if hex_str_16 == "c00000c00000c1ff00c78000ec0000f80000f0000040000":
                                    # print("find it")
                                    if ok:
                                        bk = True
                                    # print(len(hexstr_2))
                                if "@" in tab:
                                    c = p_hexstr_2
                                    c += hexstr_2
                                    hexstr_2 = c
                                word = data_tuple[1]
                                x = int(data_tuple[4])
                                y = int(data_tuple[3])
                                image_array = binstr_to_nparray(hexstr_2, x, y)
                                if bk:
                                    pass
                                    # self.show(image_array)
                                new_X_t = self.matchTemplate(cj, image_array, M, getone=True)
                                if new_X_t != (-1, -1):
                                    strs += word
                                    bno_found = False
                                    break
                        if bno_found:
                            strs += "?"
            print("当前字符串:", strs)
            return strs

    def matchTemplate(self, tpl, target, tolerance=0.2, getone=True):
        methods = [cv2.TM_SQDIFF_NORMED]  # 3种模板匹配方法 cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF_NORMED
        th, tw = target.shape[:2]

        for md in methods:
            if getone:
                try:
                    res = cv2.matchTemplate(tpl, target, md)
                    ok = True
                except cv2.error as e:
                    ok = False
                    return (-1, -1)

                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
                if min_val > tolerance:
                    return (-1, -1)
                else:
                    pass
                if md == cv2.TM_SQDIFF_NORMED:
                    tl = min_loc
                else:
                    tl = max_loc
                br = (tl[0] + tw, tl[1] + th)  # br是矩形右下角的点的坐标
                a = int((tl[0] + int(tw / 2)))
                b = int((tl[1] + int(th / 2)))
                return a, b
            else:
                res = cv2.matchTemplate(tpl, target, cv2.TM_SQDIFF_NORMED)
                right_bottom_list = list()
                loc = np.where(res <= tolerance)
                for pt in zip(*loc[::-1]):  # *号表示可选参数
                    right_bottom = (int((pt[0] + int(tw / 2))), int((pt[1] + int(th / 2))))
                    right_bottom_list.append(right_bottom)
                return right_bottom_list
        return (-1, -1)

    def __Ocr(self,tpl, scx_rgb, x1, y1, x2, y2):

        MeanRgb = list()
        if "#" in scx_rgb:
            __scx_rgb = scx_rgb.split("#")
            for i in __scx_rgb:
                se_rgb_tupe = i.split(",")
                __mean_s_r = int(se_rgb_tupe[0][0:2], 16)
                __mean_s_g = int(se_rgb_tupe[0][2:4], 16)
                __mean_s_b = int(se_rgb_tupe[0][4:6], 16)
                __mean_m_r = int(se_rgb_tupe[1][0:2], 16)
                __mean_m_g = int(se_rgb_tupe[1][2:4], 16)
                __mean_m_b = int(se_rgb_tupe[1][4:6], 16)
                MeanRgb.append([__mean_s_r, __mean_s_g, __mean_s_b, __mean_m_r, __mean_m_g, __mean_m_b])
        else:
            se_rgb_tupe = scx_rgb.split(",")
            __mean_s_r = int(se_rgb_tupe[0][0:2], 16)
            __mean_s_g = int(se_rgb_tupe[0][2:4], 16)
            __mean_s_b = int(se_rgb_tupe[0][4:6], 16)
            __mean_m_r = int(se_rgb_tupe[1][0:2], 16)
            __mean_m_g = int(se_rgb_tupe[1][2:4], 16)
            __mean_m_b = int(se_rgb_tupe[1][4:6], 16)
            MeanRgb.append([__mean_s_r, __mean_s_g, __mean_s_b, __mean_m_r, __mean_m_g, __mean_m_b])

        binary = np.zeros((abs(y2 - y1), abs(x2 - x1)), dtype=np.uint8)
        bin_2_ = self.rgb_to_hexstr_2(tpl, binary, np.array(MeanRgb), x1, y1, x2, y2)
        return bin_2_


    
    
